package com.onpositive.knowledge.model.value.audits;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;

public class ValueSequenceOrderingAudit extends AbstractUniverseAudit
{
	private static final long serialVersionUID = 7541894123290423178L;
	
	public final static String ID = "value-sequence-ordering-audit" ;

	@Override
	public void perform(Iterable<IProperty> properties,	Iterable<Object> objects, AbstractAuditResult auditResult)
	{	
		if( !(auditResult instanceof OwnAuditResult))
			return ;	
		
		iterateProperties(properties, objects, auditResult, 0);
		
		((OwnAuditResult)auditResult).clearTemporaryList() ;
	}

	//@Override
	public void iterateProperties(Iterable<IProperty> properties, Iterable<Object> objects, AbstractAuditResult result, int ind)
	{
		OwnAuditResult _res = (OwnAuditResult) result ;
		for( IProperty prop : properties ){
			
			String name = prop.getMeta().getSingleValue( "id", String.class, null ) ;
			
			Boolean isService = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_SERVICE_PROPERTY, Boolean.class, null) ;
			if( isService != null && isService )
				continue ;
			
			Boolean isDepricated = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_DEPRICATED_LABEL, Boolean.class, null);
			if( isDepricated != null && isDepricated )
				continue ;
			
			Boolean isIdent = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_IDENTIFICATOR, Boolean.class, null);
			if( isIdent != null && !isIdent )
				continue ;
			
			_res.clearTemporaryList() ;
			//iterateObjects( prop, objects, result, ind );			
			
			processLinks( prop, _res ) ;
			result.setLooksApplyable(true) ;						
		}
	}
	
	private void processLinks( IProperty prop, OwnAuditResult result ) {		
		
		ArrayList<ParsedValueSequence> completeSet =  result.getCompleteSet() ;
		if( completeSet == null || completeSet.size() == 0 )
			return ;
		
		HashMap<String,Boolean> correctionMap =  result.getCorrectionsMapForCompletion( prop.getId() ) ;		
		HashMap<String,int[]> map = createMap( completeSet ) ;

		for( Map.Entry<String, int[]> entry : map.entrySet() )
		{
			int[] val = entry.getValue() ;
			if( val[0] == 0 || val[1] == 0 )
				continue ;
			
			String keyStr = entry.getKey() ;
			boolean usualyOccursInAlphabeticalOrder = val[0] > val[1];
			correctionMap.put( keyStr, usualyOccursInAlphabeticalOrder ) ;
		}
		
		result.clearTemporaryList() ;
	}

	private ArrayList<ParsedString> split(String str, HashSet<String> linkSet)
	{
		ArrayList<ParsedString> parts = new ArrayList<ParsedString>() ;
		int prev = 0 ;
		for( int i = str.indexOf("[[") ; i >= 0 ; i = str.indexOf("[[",prev)   )
		{
			prev = str.indexOf("]]",i ) ;
			if( prev < 0 )
				return null ;		
			
			prev += 2;
			
			String fullLinkStringWithBrackets = str.substring(i, prev ) ;
			
			if( !linkSet.contains(fullLinkStringWithBrackets) )
				return null ;
			
			parts.add( new ParsedString(fullLinkStringWithBrackets,"ord-audit") ) ;
		}
		
		return parts.size() > 1 ? parts : null ;
	}

	public String buildKeyWord(String fullLinkStringWithBrackets) {
		int ind = fullLinkStringWithBrackets.indexOf(" ") ;
		String keyWord ;
		if ( ind < 0 )
			keyWord = fullLinkStringWithBrackets.toLowerCase() ;
		else
			keyWord = fullLinkStringWithBrackets.substring(0,ind) ;
		return keyWord;
	}

	private HashMap<String, int[]> createMap( ArrayList<ParsedValueSequence> completeLinkArray )
	{
		HashMap<String,int[]> result = new HashMap<String, int[]>() ;
		
		for( ParsedValueSequence ps : completeLinkArray )
		{
			LinkedHashSet<ParsedValue> set = (LinkedHashSet<ParsedValue>) ps.value();
			int size = set.size();
			if( size < 2 )
				continue ;
			
			ParsedValue[] valArr = new ParsedValue[size] ;
			set.toArray(valArr) ;			
			for( int i = 1 ; i < size ; i++ )
			{
				if( !(valArr[i] instanceof ParsedString) ){
					i++ ;
					continue ;
				}
				
				if( !(valArr[i-1] instanceof ParsedString) )
					continue ;				
				
				String s0 = ((ParsedString)valArr[i-1]).getValueAsString() ; 
				String s1 = ((ParsedString)valArr[i  ]).getValueAsString() ;
				
				boolean firstIsSmallerThenSecond = s0.compareTo(s1) < 0 ;
				String keyString = firstIsSmallerThenSecond ? s0+s1 : s1+s0 ;
				int ind = firstIsSmallerThenSecond ? 0 : 1 ;
				int[] counter = result.get(keyString) ;
				if( counter == null )
				{
					counter = new int[]{0,0} ;
					result.put(keyString, counter) ;
				}
				counter[ind]++ ;
			}
		}
		

		return result ;
	}	

	@Override
	public AbstractAuditResult createAuditResult() {
		return new OwnAuditResult( this );
	}

	@Override
	public String getId() {
		return ID;
	}
	
	@Override
	protected void process( IProperty prop, Object val, Map<String,Object> metaInfo, int index) {
		
//		if( !(val instanceof ParsedValueSequence) )
//			return ;
//		
//		if( !(result instanceof OwnAuditResult) )
//			return ;
//		
//		OwnAuditResult _res = (OwnAuditResult) result ;
//		ParsedValueSequence ps = (ParsedValueSequence) val ;
//
//		_res.getCompleteSet().add(ps) ;
	}

	private boolean isSingleLink(String str) {
		
		int i0 = str.indexOf("[[") ;
		if( i0 != 0 )
			return false ;
		
		int i1 = str.indexOf("]]") ;
		if( i1 != str.length()-2 )
			return false ;
		
		return true;
	}

	protected Class<?>[] createNecessaryClasses() {
		return new Class<?>[]{ ParsedValueSequence.class };
	}

	protected Class<?>[] createTargetClasses() {
		return new Class<?>[]{ ParsedValueSequence.class };
	}
	
	
	public static class OwnAuditResult extends AbstractAuditResult {
		
		
		/**
		 * 
		 */
		private static final long serialVersionUID = -3669061332202652749L;

		public OwnAuditResult( IUniverseAudit audit ) {
			super( audit);
		}

		public OwnAuditResult( IProperty prop )
		{
			super( prop );
		}

		HashMap<String, HashMap<String,Boolean>> correctionsMap = new HashMap<String,HashMap<String, Boolean>>() ;
		//tmp
		ArrayList<ParsedValueSequence> completeSet = new ArrayList<ParsedValueSequence>() ;
		
		public ArrayList<ParsedValueSequence> getCompleteSet() {
			return completeSet;
		}

		public void clearTemporaryList() {
			completeSet.clear() ;
		}

		public HashMap<String, Boolean> getCorrectionsMapForCompletion( String str ) {
			HashMap<String, Boolean> map = correctionsMap.get(str);
			if( map == null )
			{
				map = new HashMap<String,Boolean>() ;
				correctionsMap.put(str,map) ;
			}
			return map;
		}

		public HashMap<String,Boolean> getCorrectionsMap( String str )
		{
			return correctionsMap.get(str);
		}

	}


	@Override
	public Set<String> getRequiredAudits() {
		// TODO Auto-generated method stub
		return null;
	}

}

